﻿using System.ComponentModel;

namespace System
{
    /// <summary>
    /// 类型的一些帮助方法
    /// </summary>
    public static class TypeHelper
    {
        /// <summary>
        /// 强制把 value 的值变换为 desiredType
        /// </summary>
        /// <param name="desiredType"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object CoerceValue(Type desiredType, object value)
        {
            value = value == null ?
                GetDefaultValue(desiredType) :
                CoerceValue(desiredType, value.GetType(), value);
            return value;
        }

        /// <summary>
        /// 获取指定类型的默认值。
        /// </summary>
        /// <param name="targetType">Type of the target.</param>
        /// <returns></returns>
        public static object GetDefaultValue(Type targetType)
        {
            if (targetType.IsValueType)
                return Activator.CreateInstance(targetType);
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="desiredType"></param>
        /// <param name="valueType"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object CoerceValue(Type desiredType, Type valueType, object value)
        {
            if (desiredType.IsAssignableFrom(valueType))
                return value;
            if (desiredType == typeof(string))
                return value != null ? value.ToString() : null;
            if (desiredType.IsGenericType && desiredType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                desiredType = Nullable.GetUnderlyingType(desiredType);
                if (value == null || value is string && value as string == string.Empty)
                    return null;
            }
            if (desiredType.IsEnum)
                return Enum.Parse(desiredType, value.ToString());
            if ((desiredType.IsPrimitive || desiredType == typeof(Decimal)) && value is string && string.IsNullOrEmpty(value as string))
                value = (object)0;
            if (desiredType == typeof(Guid) && value is string)
                return (object)Guid.Parse(value as string);
            try
            {
                return Convert.ChangeType(value, desiredType);
            }
            catch
            {
                TypeConverter converter = TypeDescriptor.GetConverter(desiredType);
                if (converter != null && converter.CanConvertFrom(valueType))
                    return converter.ConvertFrom(value);
                throw;
            }
        }
    }
}